// 条款49：了解new-handler的行为
// 核心概念
// 当operator new无法满足内存分配请求时，它会在抛出异常前调用一个称为"new-handler"的函数。
// 这个函数是由程序员通过std::set_new_handler设置的，提供了一种自定义内存分配失败处理策略的机制。

// new-handler的工作原理
// 设置new-handler的函数原型
namespace std
{
    using new_handler = void (*)(); //(*new_handler) 表示这是一个名为new_handler的函数指针
    new_handler set_new_handler(new_handler p) noexcept;
}
// 当operator new无法分配足够内存时，它会：
// 1.调用当前的new-handler函数
// 2.如果new-handler为null，抛出std::bad_alloc异常
// 3.如果new-handler不为null，则期望new-handler执行某些操作后返回，然后operator new会再次尝试分配内存

// 一个有效的new-handler应该做什么
// 一个设计良好的new-handler应该做以下事情之一：
// 1.让更多内存可用：释放一些预留的内存池
// 2.安装另一个new-handler：如果当前handler无法提供更多内存，可以安装另一个handler
// 3.卸载new-handler：通过调用set_new_handler(nullptr)，使后续内存分配失败时直接抛出异常
// 4.抛出异常：抛出std::bad_alloc或其派生类的异常
// 5.不返回：调用abort()或exit()终止程序

// 实现示例
// 一个简单的new-handler实现
void outOfMemory()
{
    std::cerr << "Memory allocation failed, terminating program\n";
    std::abort();
}

// 在程序开始时安装
int main()
{
    std::set_new_handler(outOfMemory);

    // 现在，当内存分配失败时，会调用outOfMemory函数
    // ...

    return 0;
}

// 类专属的new-handler
// 标准的set_new_handler是全局的，但有时我们希望为不同的类提供不同的内存分配失败处理策略。
// 可以通过以下模式实现：
class Widget
{
public:
    static void outOfMemory(); // Widget专属的new-handler

    // 重载operator new
    static void *operator new(std::size_t size) throw(std::bad_alloc);

    // 设置和获取Widget专属的new-handler
    static std::new_handler set_new_handler(std::new_handler p) throw();

private:
    static std::new_handler currentHandler; // Widget专属的new-handler
};

// 静态成员初始化
std::new_handler Widget::currentHandler = nullptr;

// 实现set_new_handler
std::new_handler Widget::set_new_handler(std::new_handler p) throw()
{
    std::new_handler oldHandler = currentHandler;
    currentHandler = p;
    return oldHandler;
}

// 实现operator new
void *Widget::operator new(std::size_t size) throw(std::bad_alloc)
{
    // 保存全局new-handler
    std::new_handler globalHandler = std::set_new_handler(currentHandler);

    void *memory;
    try
    {
        // 尝试分配内存，如果失败，会调用Widget专属的new-handler
        memory = ::operator new(size);
    }
    catch (...)
    {
        // 恢复全局new-handler
        std::set_new_handler(globalHandler);
        throw; // 重新抛出异常
    }

    // 恢复全局new-handler
    std::set_new_handler(globalHandler);
    return memory;
}